package com.example.routeplansystem.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import com.example.routeplansystem.dao.NodeDao;
import com.example.routeplansystem.entity.po.NodePojo;
import com.example.routeplansystem.exception.ServiceException;

import lombok.Data;


/**
 * @author 唐海军
 * @create 2022-08-30 16:08
 */

@Component
public class DistanceUtil {

    public static String distanceSource = "";

    @Resource
    private NodeDao nodeDao;

    @Value("${distance.source:}")
    public void setDistanceSource(String source) {
        distanceSource = source;
    }

    public static Integer getDistance(double start_lng, double start_lat, double end_lng, double end_lat) {
        if ("EuclideanDistance".equals(distanceSource)) {
            return getEuclideanDistance(start_lng, start_lat, end_lng, end_lat);
        }
        HashMap<String, List<HashMap<String, Double>>> requestBody = new HashMap<>();
        HashMap<String, Double> startNode = new HashMap<>();
        HashMap<String, Double> endNode = new HashMap<>();
        startNode.put("lng", start_lng);
        startNode.put("lat", start_lat);
        endNode.put("lng", end_lng);
        endNode.put("lat", end_lat);
        requestBody.put("start", new ArrayList() {{
            add(startNode);
        }});
        requestBody.put("end", new ArrayList() {{
            add(endNode);
        }});
        //header参数
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        //组装
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(15000);
        factory.setReadTimeout(5000);
        RestTemplate restTemplate = new RestTemplate(factory);
        HttpEntity<HashMap> request = new HttpEntity<>(requestBody, headers);
        ResponseEntity<RequestBody> responseEntity = restTemplate.exchange("http://www.lczwyx.top:7002/msgSearch"
                , HttpMethod.POST, request, RequestBody.class);
        RequestBody body = responseEntity.getBody();
        Integer distance = body.getData().get(0).get(0).getDistance();
        return distance;
    }

    public static Integer getDistance(NodePojo startNode, NodePojo endNode) {
        if ("EuclideanDistance".equals(distanceSource)) {
            return getEuclideanDistance(startNode.getLng(), startNode.getLat(), endNode.getLng(), endNode.getLat());
        }
        Integer startId = startNode.getNodeId();
        Integer endId = endNode.getNodeId();
        HashMap<String, List<Integer>> requestBody = new HashMap<>();
        requestBody.put("start", new ArrayList() {{
            add(startId);
        }});
        requestBody.put("end", new ArrayList() {{
            add(endId);
        }});
        //header参数
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        //组装
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(15000);
        factory.setReadTimeout(5000);
        RestTemplate restTemplate = new RestTemplate(factory);
        HttpEntity<HashMap> request = new HttpEntity<>(requestBody, headers);
        ResponseEntity<RequestBody> responseEntity = null;
        try {
            responseEntity = restTemplate.exchange("http://www.lczwyx.top:7002/idSearch"
                    , HttpMethod.POST, request, RequestBody.class);
        } catch (HttpServerErrorException e) {
            throw new ServiceException("点不存在!!!");
        } catch (RestClientException e) {
            e.printStackTrace();
        }
        RequestBody body = responseEntity.getBody();
        Integer distance = body.getData().get(0).get(0).distance;
        return distance;
    }

    public static int[][] getDistanceByIdList(List<Integer> startId, List<Integer> endId) {
        HashMap<String, List<Integer>> requestBody = new HashMap<>();
        requestBody.put("start", startId);
        requestBody.put("end", endId);
        //header参数
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        //组装
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(15000);
        factory.setReadTimeout(5000);
        RestTemplate restTemplate = new RestTemplate(factory);
        HttpEntity<HashMap> request = new HttpEntity<>(requestBody, headers);
        ResponseEntity<RequestBody> responseEntity = null;
        try {
            responseEntity = restTemplate.exchange("http://www.lczwyx.top:7002/idSearch"
                    , HttpMethod.POST, request, RequestBody.class);
        } catch (HttpServerErrorException e) {
            throw new ServiceException("点不存在!!!");
        } catch (RestClientException e) {
            e.printStackTrace();
        }
        RequestBody body = responseEntity.getBody();
        List<List<RequestBody.Result>> data = body.getData();
        int[][] matrix = new int[startId.size()][endId.size()];
        for (int i = 0; i < data.size(); i++) {
            List<RequestBody.Result> results = data.get(i);
            for (int j = 0; j < results.size(); j++) {
                matrix[j][i] = results.get(j).distance;
            }
        }
        return matrix;
    }

    public static Integer getEuclideanDistance(double start_lng, double start_lat, double end_lng, double end_lat) {
        // 地球半径，单位是米
        double earthRadius = 6371.01*1000;

        // 将角度转换为弧度
        double latDistance = Math.toRadians(end_lat - start_lat);
        double longDistance = Math.toRadians(end_lng - start_lng);

        // 应用Haversine公式
        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(start_lat)) * Math.cos(Math.toRadians(end_lat))
                * Math.sin(longDistance / 2) * Math.sin(longDistance / 2);

        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        // 最终结果
        return (int)(earthRadius * c);

    }

    @Data
    private static class RequestBody {
        private Integer status;
        private List<List<Result>> data;

        @Data
        private static class Result {
            private Integer origin_id;
            private Integer dest_id;
            private Integer distance;
            private Integer duration;

        }
    }

}

